package idalloc

import (
	"maps"
	"sync"

	"github.com/cockroachdb/errors"
)

// IdAllocatorManager ID分配器管理器（单例模式）
type AllocatorManager struct {
	allocators map[string]*Allocator
	mutex      sync.RWMutex
}

var (
	allocatorManager     *AllocatorManager
	allocatorManagerOnce sync.Once
)

// GetIdAllocatorManager 获取ID分配器管理器实例
func GetIdAllocatorManager() *AllocatorManager {
	allocatorManagerOnce.Do(func() {
		allocatorManager = &AllocatorManager{
			allocators: make(map[string]*Allocator),
		}
	})
	return allocatorManager
}

// RegisterAllocator 注册ID分配器
func (m *AllocatorManager) RegisterAllocator(tableName string, config Config) {
	m.mutex.Lock()
	defer m.mutex.Unlock()
	m.allocators[tableName] = NewAllocator(config)
}

// GetAllocator 获取指定表的ID分配器
func (m *AllocatorManager) GetAllocator(tableName string) (*Allocator, error) {
	m.mutex.RLock()
	defer m.mutex.RUnlock()

	allocator, exists := m.allocators[tableName]
	if !exists {
		return nil, errors.Newf("表 %s 的ID分配器未注册", tableName)
	}
	return allocator, nil
}

// InitAllAllocators 初始化所有已注册的分配器
// func (m *AllocatorManager) InitAllAllocators(queryFuncs map[string]func() ([]int64, error)) error {
// 	m.mutex.RLock()
// 	defer m.mutex.RUnlock()

// 	for tableName, allocator := range m.allocators {
// 		queryFunc, exists := queryFuncs[tableName]
// 		if !exists {
// 			return errors.Newf("表 %s 缺少查询函数", tableName)
// 		}

// 		if err := allocator.InitUnusedIds(queryFunc); err != nil {
// 			return errors.Wrapf(err, "初始化表 %s 的ID分配器失败", tableName)
// 		}
// 	}

// 	return nil
// }

// GetAllAllocators 获取所有分配器（返回拷贝以防止外部修改）
func (m *AllocatorManager) GetAllAllocators() map[string]*Allocator {
	m.mutex.RLock()
	defer m.mutex.RUnlock()

	result := make(map[string]*Allocator, len(m.allocators))
	maps.Copy(result, m.allocators)
	return result
}

// GetAllocatorNames 获取所有分配器名称（更轻量级的选择）
func (m *AllocatorManager) GetAllocatorNames() []string {
	m.mutex.RLock()
	defer m.mutex.RUnlock()

	names := make([]string, 0, len(m.allocators))
	for name := range m.allocators {
		names = append(names, name)
	}
	return names
}
